package lib;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;

import lib.messaging.NetworkAddress;

/**
 * Provides static utility methods
 *
 * @author abhip
 *
 */
public class Utility
{
    private static final String CharSet = "US-ASCII";
    private static final String ServerDirFormatString = "ServerData_%s_%d";

    /**
     * Convert a byte[] to a string
     *
     * @param msg
     *            The byte[] to convert
     * @return The converted String
     * @throws UnsupportedEncodingException
     */
    public static String ByteArrayToString(byte[] msg)
            throws UnsupportedEncodingException {
        ArgumentValidator.IsNotNull("msg", msg);

        return new String(msg, CharSet);
    }

    /**
     * Deserializes a serializable object from byte array
     *
     * @param data
     * @return deserialized RPCInvokePacket
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Serializable Deserialize(byte[] data)
            throws IOException, ClassNotFoundException
    {
        ObjectInputStream objectInputStream = new ObjectInputStream(
                new ByteArrayInputStream(data));
        return (Serializable) objectInputStream.readObject();
    }

    /**
     * Flattens out elements in a list to string
     *
     * @param elems
     * @return
     */
    public static String FlattenListToString(List<?> elems)
    {
        if (elems == null || elems.size() == 0)
        {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < elems.size(); ++i)
        {
            sb.append(elems.get(i));
            sb.append(", ");
        }

        return sb.toString();
    }

    /**
     * Returns current working directory
     *
     * @return current working directory
     */
    public static File GetCurrentWorkingDirectory() {
        return new File(System.getProperty("user.dir"));
    }

    public static File GetServerDirectory(File serverRootDirectory, NetworkAddress serverAddress)
    {
        String serverDirName = String.format(ServerDirFormatString, serverAddress.Name(), serverAddress.Port());
        File serverDir = new File(serverRootDirectory, serverDirName);
        serverDir.mkdirs();

        return serverDir;
    }

    /**
     * Inserts and element into list and then sorts it
     * @param elem
     * @param elems
     */
    public static <T extends Comparable<? super T>> List<T> InsertElementAndSort(T elem, List<T> elems)
    {
        if (elems == null)
        {
            return null;
        }

        elems.add(elem);
        Collections.sort(elems);
        return elems;
    }

    /**
     * Serializes an object to byte array
     *
     *@param obj object to be serialized
     * @return serialized byte array
     * @throws IOException
     */
    public static byte[] Serialize(Serializable obj) throws IOException
    {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                byteArrayOutputStream);
        objectOutputStream.writeObject(obj);
        objectOutputStream.flush();
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * Sorts input list and returns sorted list
     * @param elems
     * @return
     */
    public static <T extends Comparable<? super T>> List<T> Sort(List<T> elems)
    {
        if (elems == null)
        {
            return null;
        }

        Collections.sort(elems);
        return elems;
    }

    /**
     * Convert a string to a byte[]
     *
     * @param msg
     *            The string to convert
     * @return The byte[] that the string was converted to
     * @throws UnsupportedEncodingException
     */
    public static byte[] StringToByteArray(String msg) throws UnsupportedEncodingException
    {
        ArgumentValidator.IsNotNullOrEmpty("msg", msg);

        return msg.getBytes(CharSet);
    }


}
